package com.enjoy.mediademo;

import android.Manifest;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.hardware.Camera;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureFailure;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.media.MediaRecorder;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.util.Log;
import android.util.Size;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

// 该注解表明此类需要 Android 5.0（API 级别 21，即 LOLLIPOP）及以上版本的系统支持
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class AndroidCameraSurfaceViewActivity extends AppCompatActivity implements SurfaceHolder.Callback {
    // 日志标签，方便调试时输出信息
    private static final String TAG = AndroidCameraSurfaceViewActivity.class.getSimpleName();
    // 定义请求相机权限的请求码，用于在权限请求回调中识别请求
    private static final int REQUEST_CAMERA_PERMISSION = 200;
    // 表示当前使用的相机设备对象
    private CameraDevice cameraDevice;
    // 用于录制音频和视频的媒体录制器对象
    private MediaRecorder mediaRecorder;
    // 用于显示相机预览画面的 SurfaceView 控件
    private SurfaceView surfaceView;
    // 用于控制录制开始和停止的按钮
    private Button recordButton;

    private Button captureButton;
    // 标记当前是否正在进行录制操作的布尔变量
    private boolean isRecording = false;
    // 存储当前使用相机的唯一标识符
    private String cameraId;
    // 用于在后台线程处理相机操作的 Handler 对象
    private Handler backgroundHandler;
    // 专门为相机操作创建的后台线程
    private HandlerThread backgroundThread;
    // SurfaceView 的 SurfaceHolder 对象，用于管理 Surface 并监听其状态变化
    private SurfaceHolder surfaceHolder;

    private Handler upviewHandler;

    private ImageReader imageReader;

    private CaptureRequest.Builder previewRequestBuilder;
    private CameraCaptureSession previewSession;

    // 重写 Activity 的 onCreate 方法，在活动创建时调用
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 设置当前活动的布局为 activity_camera_surfaceview.xml
        setContentView(R.layout.activity_camera_surfaceview);

        // 通过 findViewById 方法获取布局文件中的 SurfaceView 控件实例
        surfaceView = findViewById(R.id.surfaceView);
        // 通过 findViewById 方法获取布局文件中的录制按钮控件实例
        recordButton = findViewById(R.id.recordButton);

        captureButton = findViewById(R.id.captureButton);
        // 获取 SurfaceView 的 SurfaceHolder 对象
        surfaceHolder = surfaceView.getHolder();
        // 为 SurfaceHolder 添加回调监听器，以便监听 Surface 的创建、变化和销毁事件
        surfaceHolder.addCallback(this);

        // 为录制按钮设置点击监听器
        recordButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (isRecording) {
                    // 如果正在录制，则调用停止录制的方法
                    stopRecording();
                } else {
                    // 如果未录制，则调用开始录制的方法
                    startRecording();
                }
            }
        });

        captureButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                takePhoto();
            }
        });

        upviewHandler=new AndroidCameraSurfaceViewActivity.UpviewHandler(this);
    }

    // 重写 Activity 的 onResume 方法，在活动恢复到前台时调用
    @Override
    protected void onResume() {
        super.onResume();
        // 启动用于处理相机操作的后台线程
        startBackgroundThread();
    }

    // 重写 Activity 的 onPause 方法，在活动暂停时调用
    @Override
    protected void onPause() {
        // 停止用于处理相机操作的后台线程
        stopBackgroundThread();
        if (isRecording) {
            // 如果正在录制，先停止录制操作
            stopRecording();
        }
        super.onPause();
    }

    // 定义相机设备状态回调对象，用于监听相机设备的打开、断开连接和出错等状态变化
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(@NonNull CameraDevice camera) {
            // 当相机设备成功打开时，将相机设备对象赋值给 cameraDevice 变量
            cameraDevice = camera;
            if (!isRecording) {
                // 如果当前没有在录制，调用创建相机预览的方法
                createCameraPreview();
            }
        }

        @Override
        public void onDisconnected(@NonNull CameraDevice camera) {
            // 当相机设备断开连接时，关闭相机设备并将 cameraDevice 置为 null
            camera.close();
            cameraDevice = null;
        }

        @Override
        public void onError(@NonNull CameraDevice camera, int error) {
            // 当相机设备出现错误时，关闭相机设备并将 cameraDevice 置为 null
            camera.close();
            cameraDevice = null;
        }
    };

    // 打开相机设备的方法
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private void openCamera() {
        // 获取系统的相机管理服务实例
        CameraManager manager = (CameraManager) getSystemService(CAMERA_SERVICE);
        try {
            // 获取指定索引（这里是 3）的相机 ID
            cameraId = manager.getCameraIdList()[3];
            // 获取该相机的特性信息
            CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
            StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
           /* Size largest = map.getOutputSizes(ImageFormat.JPEG)[0];
            imageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(), ImageFormat.JPEG, 2);
            imageReader.setOnImageAvailableListener(onImageAvailableListener, backgroundHandler);*/
            // 获取JPEG格式所有可用的输出尺寸
            Size[] jpegSizes = map.getOutputSizes(ImageFormat.JPEG);

            // 初始化最大的尺寸，开始时可以设置为null或者列表中的第一个尺寸（但不推荐直接假设第一个就是最大的）
            Size largest = null;
            int largestArea = 0;

            // 遍历尺寸列表，找出面积最大的尺寸
            for (Size size : jpegSizes) {
                int area = size.getWidth() * size.getHeight();
                if (area > largestArea) {
                    largestArea = area;
                    largest = size;
                }
            }

            // 现在largest变量中存储的是最大的JPEG输出尺寸
            if (largest != null) {
                imageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(), ImageFormat.JPEG, /* 缓冲区数量，根据需要设置，例如2 */ 2);
                imageReader.setOnImageAvailableListener(onImageAvailableListener, backgroundHandler);
            } else {
                Log.e(TAG, "takePhoto:err");
                // 处理错误情况，例如没有可用的JPEG尺寸
                // 这通常不应该发生，除非相机配置有问题或者API使用不当
            }

            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                // 如果没有相机权限，则请求相机和录音权限
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO}, REQUEST_CAMERA_PERMISSION);
                return;
            }
            // 打开指定 ID 的相机设备，并传入状态回调和后台处理的 Handler
            manager.openCamera(cameraId, stateCallback, backgroundHandler);
        } catch (CameraAccessException e) {
            // 捕获相机访问异常并打印堆栈信息
            e.printStackTrace();
        }
    }

    // 创建相机预览会话的方法
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private void createCameraPreview() {
        try {
            // 获取 SurfaceHolder 对应的 Surface 对象
            Surface surface = surfaceHolder.getSurface();
            // 创建一个用于预览的捕获请求构建器
            previewRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            // 将 Surface 对象添加到预览请求的目标中
            previewRequestBuilder.addTarget(surface);

            // 创建相机捕获会话，传入包含预览 Surface 的列表和会话状态回调
            cameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(@NonNull CameraCaptureSession session) {
                    previewSession = session;
                    if (cameraDevice == null) return;
                    try {
                        // 构建预览请求
                        CaptureRequest previewRequest = previewRequestBuilder.build();
                        // 设置会话以重复执行预览请求，实现持续预览
                        session.setRepeatingRequest(previewRequest, null, backgroundHandler);
                    } catch (CameraAccessException e) {
                        // 捕获相机访问异常并打印堆栈信息
                        e.printStackTrace();
                    }
                }

                @Override
                public void onConfigureFailed(@NonNull CameraCaptureSession session) {
                    // 当会话配置失败时，显示提示信息
                    Toast.makeText(AndroidCameraSurfaceViewActivity.this, "Configuration change", Toast.LENGTH_SHORT).show();
                }
            }, null);
        } catch (CameraAccessException e) {
            // 捕获相机访问异常并打印堆栈信息
            e.printStackTrace();
        }
    }

    // 开始录制视频的方法
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private void startRecording() {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED ||
                ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            // 如果没有录音或相机权限，则请求这些权限
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION);
            return;
        }
        try {
            // 设置媒体录制器的参数
            setUpMediaRecorder();
            // 获取用于预览的 Surface 对象
            Surface previewSurface = surfaceHolder.getSurface();
            // 获取媒体录制器对应的 Surface 对象
            Surface recorderSurface = mediaRecorder.getSurface();

            // 创建一个用于录制的捕获请求构建器
            CaptureRequest.Builder previewRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
            // 将预览 Surface 和录制 Surface 都添加到请求目标中
            previewRequestBuilder.addTarget(previewSurface);
            previewRequestBuilder.addTarget(recorderSurface);

            // 创建相机捕获会话，传入包含预览和录制 Surface 的列表和会话状态回调
            cameraDevice.createCaptureSession(Arrays.asList(previewSurface, recorderSurface), new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(@NonNull CameraCaptureSession session) {
                    try {
                        // 构建录制请求
                        CaptureRequest previewRequest = previewRequestBuilder.build();
                        // 设置会话以重复执行录制请求
                        session.setRepeatingRequest(previewRequest, null, backgroundHandler);
                        // 启动媒体录制器开始录制
                        mediaRecorder.start();
                        // 将录制状态标记为正在录制
                        isRecording = true;
                        // 修改录制按钮的文本为停止录制
                        upviewHandler.sendEmptyMessage(1);
                        //recordButton.setText("Stop Recording");
                    } catch (CameraAccessException e) {
                        // 捕获相机访问异常并打印堆栈信息
                        e.printStackTrace();
                    }
                }

                @Override
                public void onConfigureFailed(@NonNull CameraCaptureSession session) {
                    // 当会话配置失败时，显示提示信息
                    Toast.makeText(AndroidCameraSurfaceViewActivity.this, "Configuration change", Toast.LENGTH_SHORT).show();
                }
            }, backgroundHandler);
        } catch (CameraAccessException | IOException e) {
            // 捕获相机访问异常或 IO 异常并打印堆栈信息
            e.printStackTrace();
        }
    }

    // 设置媒体录制器参数的方法
    private void setUpMediaRecorder() throws IOException {
        // 创建媒体录制器实例
        mediaRecorder = new MediaRecorder();
        // 设置音频源为麦克风
        mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        // 设置视频源为 Surface
        mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
        // 设置输出格式为 MPEG_4
        mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        // 创建输出文件对象，存储在外部存储的电影目录下
        File outputFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES), "video1.mp4");
        // 设置输出文件的路径
        mediaRecorder.setOutputFile(outputFile.getAbsolutePath());
        // 设置视频编码比特率
        mediaRecorder.setVideoEncodingBitRate(10000000);
        // 设置视频帧率
        mediaRecorder.setVideoFrameRate(30);
        // 设置视频尺寸
        mediaRecorder.setVideoSize(640, 480);
        // 设置视频编码器为 H264
        mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
        // 设置音频编码器为 AAC
        mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
        // 准备媒体录制器
        mediaRecorder.prepare();
    }

    // 停止录制视频的方法
    private void stopRecording() {
        if (isRecording) {
            // 将录制状态标记为停止录制
            isRecording = false;
            // 修改录制按钮的文本为开始录制
            recordButton.setText("Start Recording");
            // 停止媒体录制器
            mediaRecorder.stop();
            // 重置媒体录制器，以便下次使用
            mediaRecorder.reset();
            // 重新创建相机预览
            createCameraPreview();
        }
    }

    // 启动后台线程的方法
    private void startBackgroundThread() {
        // 创建一个名为 CameraBackground 的后台线程
        backgroundThread = new HandlerThread("CameraBackground");
        // 启动后台线程
        backgroundThread.start();
        // 创建一个关联到后台线程消息队列的 Handler 对象
        backgroundHandler = new Handler(backgroundThread.getLooper());
    }

    // 停止后台线程的方法
    private void stopBackgroundThread() {
        // 安全地停止后台线程
        backgroundThread.quitSafely();
        try {
            // 等待后台线程结束
            backgroundThread.join();
            // 将后台线程对象置为 null
            backgroundThread = null;
            // 将后台处理的 Handler 对象置为 null
            backgroundHandler = null;
        } catch (InterruptedException e) {
            // 捕获线程中断异常并打印堆栈信息
            e.printStackTrace();
        }
    }

    // 处理权限请求结果的回调方法
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_CAMERA_PERMISSION) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 如果相机权限被授予，调用打开相机的方法
                openCamera();
            } else {
                // 如果相机权限被拒绝，显示权限被拒的提示信息
                Toast.makeText(this, "Permission denied", Toast.LENGTH_SHORT).show();
            }
        }
    }

    // SurfaceHolder.Callback 接口方法，当 Surface 被创建时调用
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // 调用打开相机的方法
        openCamera();
    }

    // SurfaceHolder.Callback 接口方法，当 Surface 的格式或大小发生变化时调用
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        // 这里可以处理 Surface 变化的逻辑，目前暂时为空
    }

    // SurfaceHolder.Callback 接口方法，当 Surface 被销毁时调用
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        if (cameraDevice != null) {
            // 如果相机设备不为空，关闭相机设备并将其置为 null
            cameraDevice.close();
            cameraDevice = null;
        }
    }


    // 该方法需要 Android 5.0（API 级别 21，即 LOLLIPOP）及以上版本支持，用于执行拍照操作
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private void takePhoto() {
        // 检查相机设备是否为空，如果为空则直接返回，不执行拍照操作
        if (cameraDevice == null) return;
        try {
            // 创建一个用于拍照的捕获请求构建器，使用 TEMPLATE_STILL_CAPTURE 模板，适用于拍摄静态照片
            CaptureRequest.Builder captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
            // 将 ImageReader 的 Surface 添加到捕获请求的目标中，这样相机捕获的图像数据会发送到 ImageReader
            captureRequestBuilder.addTarget(imageReader.getSurface());

            // 通过相机管理器获取当前相机设备的特性信息
            CameraCharacteristics characteristics = ((CameraManager) getSystemService(CAMERA_SERVICE)).getCameraCharacteristics(cameraDevice.getId());
            // 根据相机特性和设备的旋转方向，设置捕获请求中 JPEG 图像的方向，确保照片方向正确
            captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(characteristics));

            // 为了避免 “CaptureRequest contains unconfigured Input/Output Surface!” 错误，
            // 创建一个列表用于存储所有需要的 Surface，确保在创建会话时包含所有必要的 Surface
            List<Surface> surfaces = new ArrayList<>();
            // 将 SurfaceView 的 Surface 添加到列表中，用于相机预览
            surfaces.add(surfaceHolder.getSurface());
            // 将 ImageReader 的 Surface 添加到列表中，用于接收拍照的图像数据
            surfaces.add(imageReader.getSurface());

            // 使用包含所有必要 Surface 的列表创建相机捕获会话
            cameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {
                // 当捕获会话配置成功时调用此方法
                @Override
                public void onConfigured(@NonNull CameraCaptureSession session) {
                    try {
                        // 使用捕获请求构建器构建最终的捕获请求
                        CaptureRequest captureRequest = captureRequestBuilder.build();
                        // 会话开始执行捕获操作，传入捕获请求、捕获回调和后台处理的 Handler
                        session.capture(captureRequest, captureCallback, backgroundHandler);
                    } catch (CameraAccessException e) {
                        // 捕获相机访问异常并打印堆栈信息
                        e.printStackTrace();
                    }
                }

                // 当捕获会话配置失败时调用此方法
                @Override
                public void onConfigureFailed(@NonNull CameraCaptureSession session) {
                    // 显示一个 Toast 提示用户捕获会话配置失败
                    Toast.makeText(AndroidCameraSurfaceViewActivity.this, "Capture session configuration failed", Toast.LENGTH_SHORT).show();
                }
            }, backgroundHandler);
        } catch (CameraAccessException e) {
            // 捕获相机访问异常并打印堆栈信息
            e.printStackTrace();
        }
    }

    private int getOrientation(CameraCharacteristics characteristics) {
        int sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
        int deviceRotation = getWindowManager().getDefaultDisplay().getRotation();
        // 计算最终的图片方向
        return (sensorOrientation + deviceRotation * 90) % 360;
    }

    private final ImageReader.OnImageAvailableListener onImageAvailableListener = new ImageReader.OnImageAvailableListener() {
        @Override
        public void onImageAvailable(ImageReader reader) {
            Image image = reader.acquireLatestImage();
            ByteBuffer buffer = image.getPlanes()[0].getBuffer();
            byte[] bytes = new byte[buffer.remaining()];
            buffer.get(bytes);
            FileOutputStream output = null;
            Log.e(TAG, "onImageAvailable:path "+Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES));
            try {
                File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "photo_" + System.currentTimeMillis() + ".jpg");
                output = new FileOutputStream(file);
                output.write(bytes);
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                image.close();
                if (null != output) {
                    try {
                        output.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    };

    private final CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() {
        @Override
        public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
            Toast.makeText(AndroidCameraSurfaceViewActivity.this, "Photo captured", Toast.LENGTH_SHORT).show();
            // 确保在回调中检查会话状态
        //    if (!isSessionClosed) {
                try {
                    //拍完照片后返还预览
                    session.setRepeatingRequest(previewRequestBuilder.build(), null, backgroundHandler);
                } catch (CameraAccessException e) {
                    e.printStackTrace();
                }
           // }
        }

        @Override
        public void onCaptureFailed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureFailure failure) {
            Toast.makeText(AndroidCameraSurfaceViewActivity.this, "Photo capture failed", Toast.LENGTH_SHORT).show();
        }
    };


    private static class UpviewHandler extends Handler {
        // 使用弱引用持有外部类的引用
        private final WeakReference<AndroidCameraSurfaceViewActivity> activityWeakReference;

        UpviewHandler(AndroidCameraSurfaceViewActivity activity) {
            activityWeakReference = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            AndroidCameraSurfaceViewActivity activity = activityWeakReference.get();
            if (activity != null) {
                // 安全地使用 activity
                ((TextView)activity.findViewById(R.id.recordButton)).setText("Stop Recording");
            }
        }
    }

}